classdef ReverbWindow < handle
    %%REVERBWINDOW Dooku Synthesizer Reverb window GUI class
    properties
        % Figure variables
        hfig;
        handles;
        
        % Setup variables
        standardCustom;
        roomInd;
        impResp;
        impRespX;
        Fs;
        
        % Design variables
        roomDim;
        micCoord;
        sourceCoord;
        reflectCoeff;
        virtualSources;
    end
    
    properties (SetObservable)
        finish;
    end
    
    methods
        
        function obj = ReverbWindow
            % Figure Load
            obj.hfig = hgload('reverbGUI.fig');
            obj.handles = guihandles(obj.hfig);
            
            % Callbacks Definitions
            set(obj.handles.reverbWindow, 'CloseRequestFcn', @(src, event) finishSelect(obj, src, event));
            set(obj.handles.standardRad, 'Callback', @(src, event) roomTypeSelect(obj, src, event));
            set(obj.handles.customRad, 'Callback', @(src, event) roomTypeSelect(obj, src, event));
            set(obj.handles.roomsMenu, 'Callback', @(src, event) roomSelect(obj, src, event));
            set(obj.handles.finishBut, 'Callback', @(src, event) finishSelect(obj, src, event));
            bg_image = imread('play.png');
            set(obj.handles.play, 'Callback', @(src, event) play(obj, src, event), 'CData', bg_image);
            bg_image = imread('stop.png');
            set(obj.handles.stop, 'Callback', @(src, event) stop(obj, src, event), 'CData', bg_image);
            set(obj.handles.rd_x, 'Callback', @(src, event) roomDimChange(obj, src, event));
            set(obj.handles.rd_y, 'Callback', @(src, event) roomDimChange(obj, src, event));
            set(obj.handles.rd_z, 'Callback', @(src, event) roomDimChange(obj, src, event));
            set(obj.handles.mc_x, 'Callback', @(src, event) micCoordChange(obj, src, event));
            set(obj.handles.mc_y, 'Callback', @(src, event) micCoordChange(obj, src, event));
            set(obj.handles.mc_z, 'Callback', @(src, event) micCoordChange(obj, src, event));
            set(obj.handles.sc_x, 'Callback', @(src, event) sourceCoordChange(obj, src, event));
            set(obj.handles.sc_y, 'Callback', @(src, event) sourceCoordChange(obj, src, event));
            set(obj.handles.sc_z, 'Callback', @(src, event) sourceCoordChange(obj, src, event));
            set(obj.handles.rf, 'Callback', @(src, event) reflectCoeffChange(obj, src, event));
            set(obj.handles.ns, 'Callback', @(src, event) virtualSourcesChange(obj, src, event));
            set(obj.handles.calculateBut, 'Callback', @(src, event) calculateSelect(obj, src, event));
            
            obj.defaultVariables();
        end
        
        function defaultVariables(obj)
            obj.standardCustom = 1;
            obj.roomInd = 1;
            obj.roomDim = [str2double(get(obj.handles.rd_x, 'String')), str2double(get(obj.handles.rd_y, 'String')), str2double(get(obj.handles.rd_z, 'String'))];
            obj.micCoord = [str2double(get(obj.handles.mc_x, 'String')), str2double(get(obj.handles.mc_y, 'String')), str2double(get(obj.handles.mc_z, 'String'))];
            obj.sourceCoord = [str2double(get(obj.handles.sc_x, 'String')), str2double(get(obj.handles.sc_y, 'String')), str2double(get(obj.handles.sc_z, 'String'))];
            obj.reflectCoeff = str2double(get(obj.handles.rf, 'String'));
            obj.virtualSources = str2double(get(obj.handles.ns, 'String'));
        end
        
        function visible(obj)
            set(obj.hfig, 'Visible', 'on');
            set(obj.hfig, 'Windowstyle', 'modal');
            obj.roomTypeSelect(0);
        end
        
        function loadData(obj, reverbData)
            obj.roomDim = reverbData.roomDim;
            obj.micCoord = reverbData.micCoord;
            obj.sourceCoord = reverbData.sourceCoord;
            obj.reflectCoeff = reverbData.reflectCoeff;
            obj.virtualSources = reverbData.virtualSources;
            obj.standardCustom = reverbData.standardCustom;
            obj.roomInd = reverbData.roomInd;
            set(obj.handles.rd_x, 'String', num2str(obj.roomDim(1)));
            set(obj.handles.rd_y, 'String', num2str(obj.roomDim(2)));
            set(obj.handles.rd_z, 'String', num2str(obj.roomDim(3)));
            set(obj.handles.mc_x, 'String', num2str(obj.micCoord(1)));
            set(obj.handles.mc_y, 'String', num2str(obj.micCoord(2)));
            set(obj.handles.mc_z, 'String', num2str(obj.micCoord(3)));
            set(obj.handles.sc_x, 'String', num2str(obj.sourceCoord(1)));
            set(obj.handles.sc_y, 'String', num2str(obj.sourceCoord(2)));
            set(obj.handles.sc_z, 'String', num2str(obj.sourceCoord(3)));
            set(obj.handles.rf, 'String', num2str(obj.reflectCoeff));
            set(obj.handles.ns, 'String', num2str(obj.virtualSources));
            if obj.standardCustom
                set(obj.handles.standardRad, 'Value', 1);
                set(obj.handles.customRad, 'Value', 0);
            else
                set(obj.handles.standardRad, 'Value', 0);
                set(obj.handles.customRad, 'Value', 1);
                obj.calculateSelect();
            end
            set(obj.handles.roomsMenu, 'Value', obj.roomInd);
            obj.refreshReverb();
        end
        
        function reverbData = saveData(obj)
            reverbData.roomDim = obj.roomDim;
            reverbData.micCoord = obj.micCoord;
            reverbData.sourceCoord = obj.sourceCoord;
            reverbData.reflectCoeff = obj.reflectCoeff;
            reverbData.virtualSources = obj.virtualSources;
            reverbData.standardCustom = obj.standardCustom;
            reverbData.roomInd = obj.roomInd;
        end
        
        function refreshReverb(obj)
            plot(obj.handles.impulseAxes, obj.impRespX, obj.impResp, 'Color', [1,1,1]);
            set(obj.handles.impulseAxes, 'Color', [0 0 0], 'XColor', [0.9 0.9 0.9], 'YColor', [0.9 0.9 0.9], 'YTick', []);
        end
        
        function obj = roomTypeSelect(obj, src, ~)
            if src
                set(src, 'Value', 1);
            end
            if get(obj.handles.standardRad, 'Value')
                set(obj.handles.roomsMenu, 'Enable', 'On');
                set(obj.handles.rd_x, 'Enable', 'Off');
                set(obj.handles.rd_y, 'Enable', 'Off');
                set(obj.handles.rd_z, 'Enable', 'Off');
                set(obj.handles.mc_x, 'Enable', 'Off');
                set(obj.handles.mc_y, 'Enable', 'Off');
                set(obj.handles.mc_z, 'Enable', 'Off');
                set(obj.handles.sc_x, 'Enable', 'Off');
                set(obj.handles.sc_y, 'Enable', 'Off');
                set(obj.handles.sc_z, 'Enable', 'Off');
                set(obj.handles.rf, 'Enable', 'Off');
                set(obj.handles.ns, 'Enable', 'Off');
                set(obj.handles.calculateBut, 'Enable', 'Off');
                obj.standardCustom = 1;
            else
                set(obj.handles.roomsMenu, 'Enable', 'Off');
                set(obj.handles.rd_x, 'Enable', 'On');
                set(obj.handles.rd_y, 'Enable', 'On');
                set(obj.handles.rd_z, 'Enable', 'On');
                set(obj.handles.mc_x, 'Enable', 'On');
                set(obj.handles.mc_y, 'Enable', 'On');
                set(obj.handles.mc_z, 'Enable', 'On');
                set(obj.handles.sc_x, 'Enable', 'On');
                set(obj.handles.sc_y, 'Enable', 'On');
                set(obj.handles.sc_z, 'Enable', 'On');
                set(obj.handles.rf, 'Enable', 'On');
                set(obj.handles.ns, 'Enable', 'On');
                set(obj.handles.calculateBut, 'Enable', 'On');
                obj.standardCustom = 0;
            end
            obj.refreshReverb();
        end
        
        function obj = roomSelect(obj, src, ~)
            obj.roomInd = get(src, 'Value');
            obj.refreshReverb();
        end
        
        function obj = finishSelect(obj, ~, ~)
            obj.finish = 1;
            set(obj.hfig, 'Visible', 'off');
            set(obj.hfig, 'Windowstyle', 'normal');
        end
        
        function obj = play(obj, ~, ~)
        end
        
        function obj = stop(obj, ~, ~)
        end
        
        function obj = roomDimChange(obj, ~, ~)
            rdAux = [str2double(get(obj.handles.rd_x, 'String')), str2double(get(obj.handles.rd_y, 'String')), str2double(get(obj.handles.rd_z, 'String'))];
            if sum(isnan(rdAux)) || sum(rdAux <= 0)
                errordlg('Room Dimensions must have positive numeric values.', 'Inconsistent error');
                set(obj.handles.rd_x, 'String', num2str(obj.roomDim(1)));
                set(obj.handles.rd_y, 'String', num2str(obj.roomDim(2)));
                set(obj.handles.rd_z, 'String', num2str(obj.roomDim(3)));
            else
                obj.roomDim = rdAux;
            end
        end
        
        function obj = micCoordChange(obj, ~, ~)
            mcAux = [str2double(get(obj.handles.mc_x, 'String')), str2double(get(obj.handles.mc_y, 'String')), str2double(get(obj.handles.mc_z, 'String'))];
            if sum(isnan(mcAux)) || sum(mcAux <= 0)
                errordlg('Microphone Coordinates must have positive numeric values.', 'Inconsistent error');
                set(obj.handles.mc_x, 'String', num2str(obj.micCoord(1)));
                set(obj.handles.mc_y, 'String', num2str(obj.micCoord(2)));
                set(obj.handles.mc_z, 'String', num2str(obj.micCoord(3)));
            else
                obj.micCoord = mcAux;
            end
        end
        
        function obj = sourceCoordChange(obj, ~, ~)
            scAux = [str2double(get(obj.handles.sc_x, 'String')), str2double(get(obj.handles.sc_y, 'String')), str2double(get(obj.handles.sc_z, 'String'))];
            if sum(isnan(scAux)) || sum(scAux <= 0)
                errordlg('Source Coordinates must have positive numeric values.', 'Inconsistent error');
                set(obj.handles.sc_x, 'String', num2str(obj.sourceCoord(1)));
                set(obj.handles.sc_y, 'String', num2str(obj.sourceCoord(2)));
                set(obj.handles.sc_z, 'String', num2str(obj.sourceCoord(3)));
            else
                obj.sourceCoord = scAux;
            end
        end
        
        function obj = reflectCoeffChange(obj, ~, ~)
            rfAux = str2double(get(obj.handles.rf, 'String'));
            if (isnan(rfAux)) || (rfAux <= 0)
                errordlg('Reflection Coefficient must be a positive numeric value.', 'Inconsistent error');
                set(obj.handles.rf, 'String', num2str(obj.reflectCoeff));
            else
                obj.reflectCoeff = rfAux;
            end
        end
        
        function obj = virtualSourcesChange(obj, ~, ~)
            nsAux = str2double(get(obj.handles.ns, 'String'));
            if (isnan(nsAux)) || (nsAux <= 0)
                errordlg('Number of virtual sources must be a positive numeric value.', 'Inconsistent error');
                set(obj.handles.ns, 'String', num2str(obj.virtualSources));
            else
                obj.virtualSources = nsAux;
            end
        end

        function obj = calculateSelect(obj, ~, ~)
            obj.Fs = 44100;
            obj.impResp = rir(obj.Fs, obj.micCoord, obj.virtualSources, obj.reflectCoeff, obj.roomDim, obj.sourceCoord);
            obj.impRespX = linspace(0, length(obj.impResp)/obj.Fs, length(obj.impResp));
            obj.refreshReverb();
        end
        
    end
    
end